#include "dragdrop.h"
#include "qgraphicssceneevent.h"
#include "qapplication.h"
#include <QDebug>
#include "itemmimedata.h"
#include <qdrag>
#include "qpixmap.h"
#include "graphicstextitem.h"
#include <QtWidgets>
#include "qevent.h"
#include "graphicsview.h"
#include "keystatus.h"
#include "additems.h"
#include "mainwindow.h"
#include "graphicsrectitem.h"
#include "actions.h"
#include "graphicsscene.h"
#include "dragitem.h"
#include "maths.h"

DragDrop * gDragDrop = NULL;


DragDrop::DragDrop(QObject *parent)
	: QObject(parent)
{
	//initDragDrop();
}

DragDrop::~DragDrop()
{

}

int DragDrop::initDragDrop()
{
	return 0;
}


bool DragDrop::viewMousePressEvent(QMouseEvent * event)
{
	resetStatus();

	//if (event->button() == Qt::LeftButton)
	{
		mPressPos = event->pos();
	}
	
	mPressedItem = getItemAtPoint(mPressPos);

	return ( isViewEvent());
}
bool DragDrop::viewMouseReleaseEvent(QMouseEvent * event)
{
	mReleasePos = event->pos();
	mReleaseItem = getItemAtPoint(mReleasePos);

	doneMouseAction(event);

	//resetStatus();
	resetOnRelease();

	gView->viewport()->update();

	return false;
}
bool DragDrop::viewMouseMoveEvent(QMouseEvent * event)
{
	mMovePos = event->pos();
	if( judgeMouseMoveAction(event) )
		return true;

	return false;
}

void DragDrop::resetStatus()
{
	mPressedItem = NULL;
	setMouseAction(MouseAction_e::eDefaultAction);
	gSence->clearSelection();

}
void DragDrop::resetOnRelease()
{
	mResizeStatus = -1;
	setMouseAction(MouseAction_e::eDefaultAction);
}
bool DragDrop::isViewEvent()
{
	bool result = false;
	Tools_e t = gActions->getCurrentTool();
	if ( t != Tools_e::eSelectTool)
	{
		result = true;
	}
	else
		result = judgePressAction();

	return result;
	
}
bool DragDrop::judgePressAction()
{
	bool result = false;
	if (mPressedItem && mResizeStatus >=0 )
	{
		result = true;
	}
	
	return result;
}


bool DragDrop::judgeMouseMoveAction(QMouseEvent * event)
{
	bool result = false;
	// left button pressed when moving, possible actions are: 
	// -drag item;
	// -draw rect;
	// -draw line;
	if ((event->buttons() & Qt::LeftButton) )
		//&& isOverDistance(mPressPos, mMovePos) )
	{
		Tools_e t = gActions->getCurrentTool();
		if( t == Tools_e::eSelectTool)
		{
			if( result = resizeItem())
				updateView();
		}
		else if ( t == Tools_e::eRectTool) // draw rect;
		{
			setMouseAction(MouseAction_e::eDrawRect);
			updateView();
		}
		else if( t == Tools_e::eLineTool) // draw line;
		{
			setMouseAction(MouseAction_e::eDrawLine);
			updateView();
		}
		else
		{
			setMouseAction(MouseAction_e::eDefaultAction);
		}
	}
	else 
	{
		Tools_e t = gActions->getCurrentTool();
		if ( t == Tools_e::eSelectTool) // draw rect;
		{
			QGraphicsItem * item = getItemAtPoint(mMovePos);
			if( item )
			{
				judgeCursorInItem(item, mMovePos);
			}
			else
			{
				gView->setCursor(Qt::ArrowCursor);
			}
		}
	}
	return result;
}
bool DragDrop::resizeItem()
{
	bool resulet = false;
	if (mPressedItem && mResizeStatus >= 0)
	{
		int margain = 4;
		int hmin = margain * 4;

		int d = mResizeStatus;
		GraphicsRectItem * item = (GraphicsRectItem *)mPressedItem;
		QPointF p = mMovePos;

		QRectF rc = item->boundingRect();
		rc.setRect(0,0,rc.width()-1,rc.height()-1);	// the real rect shap;

		QPointF p1 = item->pos();	//topLeft;
		QPointF p2 = QPointF(p1.x()+rc.width(), p1.y());	// topRight;
		QPointF p4 = QPointF(p1.x(),p1.y()+rc.height());	// bottomLeft;

		qreal dh,h,dw,w;

		if ( d == 0 )		// top;
		{
			dh = p1.y() - p.y();
			h = rc.height()+dh;
			if( h > hmin )
			{
				item->setRect(0,0,rc.width(), h);
				item->setPos(p1.x(),p1.y()-dh);
			}			
		}
		else if( d == 3)	// left;
		{
			dw = p1.x() - p.x();
			w = rc.width() + dw;
			if( w > hmin )
			{
				item->setRect(0,0, w, rc.height());
				item->setPos(p1.x()-dw, p1.y());
			}
		}
		else if ( d == 2)	// bottom;
		{
			dh =p.y() -  p4.y();
			h = rc.height()+dh;
			if( h > hmin)
				item->setRect(0,0,rc.width(), h);
			//item->setPos(p1.x(),p1.y()-dh);
		}
		else if( d == 1 )	// right;
		{
			dw =p.x() - p2.x();
			w = rc.width() + dw;
			if( w > hmin )
				item->setRect(0,0,w, rc.height());
		}
		else if( d == 4)	// topLeft;
		{
			dh = p1.y() - p.y();
			h = rc.height() + dh;
			dw = p1.x() - p.x();
			w = rc.width() + dw;
			if( h > hmin && w > hmin )
			{
				item->setRect(0,0,w, h);
				item->setPos(p1.x()-dw,p1.y()-dh);
			}
		}
		else if( d == 5 )	// topright;
		{
			dh = p1.y() - p.y();
			h = rc.height()+dh;
			dw =p.x() - p2.x();
			w = rc.width() + dw;
			if( h > hmin && w > hmin )
			{
				item->setRect(0,0,w, h);
				item->setPos(p1.x(),p1.y()-dh);
			}
		}
		else if ( d == 6)	//bottomRight;
		{
			dh =p.y() -  p4.y();
			h = rc.height()+dh;
			dw =p.x() - p2.x();
			w = rc.width() + dw;
			if( h > hmin && w > hmin )
			{
				item->setRect(0,0,w, h);
				//item->setPos(p1.x(),p1.y()-dh);
			}
		}
		else if( d == 7)	// bottomLeft;
		{
			dh =p.y() -  p4.y();
			h = rc.height()+dh;
			dw = p1.x() - p.x();
			w = rc.width() + dw;
			if( h > hmin && w > hmin )
			{
				item->setRect(0,0,w, h);
				item->setPos(p1.x()-dw,p1.y());
			}
		}

		resulet = true;
	}
	
	return resulet;
}
void DragDrop::judgeCursorInItem(QGraphicsItem * item, QPointF &p)
{
	mResizeStatus = -1;

	QPointF pos = item->pos();
	QRectF rc = item->boundingRect();
	Maths::moveRectToPoint(rc,pos);

	int w = 4;
	//
	QMargins m = QMargins(w,w,w,w);
	QRectF rc1 = rc.marginsRemoved(m);

	if (rc.contains(p) && !rc1.contains(p))
	{
		//rc1 = Maths::getMargainRect(rc,w,0);// top;
		int d = Maths::judgePointInRectMargain(rc, p, w );
		mResizeStatus = d;

		if( d == 0 || d == 2)	
		{
			gView->setCursor(Qt::SizeVerCursor);
			return ;
		}
		if( d == 1 || d == 3 )
		{
			gView->setCursor(Qt::SizeHorCursor);
			return ;
		}
		if ( d == 4 || d == 6)
		{
			gView->setCursor(Qt::SizeFDiagCursor);
			return ;
		}
		if ( d == 5 || d == 7)
		{
			gView->setCursor(Qt::SizeBDiagCursor);
			return ;
		}

		gView->setCursor(Qt::ArrowCursor);
	}
	else
	{
		gView->setCursor(Qt::ArrowCursor);
	}
}
void DragDrop::doneMouseAction(QMouseEvent * event)
{
	MouseAction_e ma = getMouseAction();
	if ( ma == MouseAction_e::eDrawRect) // draw rect;
	{
		gActions->mDrawRectByMouse->activate(QAction::Trigger);
	}
	else if( ma == MouseAction_e::eDrawLine) // draw line;
	{
		//setMouseAction(MouseAction_e::DrawLine);
		gActions->mDrawLineByMouse->activate(QAction::Trigger);
	}
	else
	{
		//setMouseAction(MouseAction_e::Default);
	}
}

// --- item; ----
bool DragDrop::itemMousePressEvent(QGraphicsSceneMouseEvent *event,QGraphicsItem * item)
{
	mPressedItem = item;

	return false;
}
bool DragDrop::itemMouseMoveEvent(QGraphicsSceneMouseEvent *event,QGraphicsItem * item)
{
	if( mPressedItem != NULL && mPressedItem == item ) {
		if (event->buttons() & Qt::LeftButton && gKeyStatus->getControl()) {
			QPointF p = event->pos();
			p = item->mapToScene(p);
			//p = gView->mapFromScene(p);
			int distance = (p - mPressPos).manhattanLength();
			qDebug() << "->itemMove distance: " 
				//<< p.x() <<","<< p.y();
				<<distance;
			if (distance >= QApplication::startDragDistance()){
				qDebug("->GraphicsTextItem.mouseMoveEvent(): distance ok.");

				performDrag();
				return true;
			}
		}
	}
	return false;
}

void DragDrop::performDrag()
{
	QDrag *drag = new QDrag(new DragItem(mPressedItem));

	QMimeData *mimeData = new ItemMimeData(mPressedItem);
	//mItem->
	//mimeData->setText(item->toPlainText());
	qDebug() << "->GraphicsTextItem.performDrag(): mimeData="<<mimeData->text();
	drag->setMimeData(mimeData);

	drag->setPixmap(QPixmap(":/images/person.png"));

	qDebug() << "->GraphicsTextItem.performDrag(): drag->exec()...";
	drag->exec();
	qDebug("->GraphicsTextItem.performDrag(): drag->exec() done.");

	//if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
	//	delete item;
}

bool DragDrop::itemDragEnterEvent(QGraphicsSceneDragDropEvent *event, QGraphicsItem * item)
{
	event->setDropAction(Qt::MoveAction);
	event->accept();

	return false;
}
bool DragDrop::itemDragMoveEvent(QGraphicsSceneDragDropEvent * event, QGraphicsItem * item)
{
	event->setDropAction(Qt::MoveAction);
	event->accept();

	return false;
}
bool DragDrop::itemDropEvent(QGraphicsSceneDragDropEvent * event, QGraphicsItem * item)
{
	const ItemMimeData * mime = qobject_cast<const ItemMimeData*>(event->mimeData());
	if( mime ) {
		QGraphicsItem * itemdrag = (mime->getItem());
		//if( item ) {
		//qDebug() << "->GraphicsRectItem.dropEvent(): item = "<< item->toPlainText();
		if (itemdrag->parentItem() != item )
		{
			itemdrag->setParentItem(item);
		}

		//}
	}
	event->setDropAction(Qt::MoveAction);
	event->accept();

	return true;
}
void DragDrop::viewDropEvent(QDropEvent *event)
{
	const ItemMimeData * mime = qobject_cast<const ItemMimeData*>(event->mimeData());
	if( mime ) {
		QGraphicsItem * item = mime->getItem();

		QPointF p = event->pos();
		qDebug() << "->GraphicsView.dropEvent: "
			<<p.x() <<","<< p.y();
		item->setPos(p);
	}
	event->setDropAction(Qt::MoveAction);
	event->accept();
}

bool DragDrop::isOverDistance(QPointF & sp, QPointF & ep)
{
	int distance = (ep - sp).manhattanLength();
	return (distance >= QApplication::startDragDistance());
}
void DragDrop::updateView()
{
	gView->viewport()->update();
}

QGraphicsItem * DragDrop::getItemAtPoint( QPointF & p)
{
	QTransform transform;
	QGraphicsItem * item = gSence->itemAt(p,transform);

	return item;
}
